﻿// *********************************************************************
// [DCOM Productions]
// [Copyright (C) DCOM Productions All rights reserved.]
// *********************************************************************

namespace BitFlex.Windows.Forms {
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;

    /// <summary>
    /// Windows Explorer Split Button
    /// </summary>
    [ToolboxBitmap(typeof(Button))]
    public partial class ExplorerSplitButton : System.Windows.Forms.Button {
        /// <summary>
        /// Instantiates a new instance of the BitFlex.Windows.Forms.ExplorerSplitButton class.
        /// </summary>
        public ExplorerSplitButton() {
            InitializeComponent();
            FlatStyle = System.Windows.Forms.FlatStyle.System;
        }

        private void InitilializeComponent() {
            SuspendLayout();
            ResumeLayout(false);
        }

        #region Platform Invoke

        [System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
        static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

        #endregion

        #region Constants

        private const int BCM_FIRST = 0x1600;
        private const int BCM_SETDROPDOWNSTATE = 0x1606;
        private const int BS_SPLITBUTTON = 0x0000000C;
        private const int WM_KILLFOCUS = 0x08;
        private const int WM_LBUTTONDOWN = 0x201;
        private const int WM_LBUTTONUP = 0x202;
        private const int WM_MOUSELEAVE = 0x2A3;
        private const int WM_NOTIFY = 0x004E;
        private const int WM_PAINT = 0x0F;

        #endregion

        #region Fields

        private int m_IsAtDropDown = 0;
        private int m_IsMouseDown = 0;
        private int m_IsDropDownPushed = 0;

        #endregion
        
        #region Properties

        protected override CreateParams CreateParams {
            get {
                CreateParams createParams = base.CreateParams;
                createParams.Style |= BS_SPLITBUTTON;
                return createParams;
            }
        }

        /// <summary>
        /// Gets or Sets the button's Drop Down Menu
        /// </summary>
        [Category("Behavior")]
        [Description("Gets or Sets the button's Drop Down Menu")]
        public ContextMenu Menu {
            get {
                return base.ContextMenu;
            }
            set {
                base.ContextMenu = value;
            }
        }

        #endregion

        #region Methods

        private void SetDropDownState(int state) {
            if (state == 0) {
                m_IsDropDownPushed = 0;
            }
            SendMessage(Handle, BCM_FIRST + 0x006, state, 0);
        }

        /// <summary>
        /// Shows the split button's menu
        /// </summary>
        public void ShowMenu() {
            if (ContextMenu != null) {
                if (ContextMenu.MenuItems.Count > 0) {
                    ContextMenu.Show(this, new Point(0, Height), LeftRightAlignment.Right);
                }
            }
        }

        protected override void WndProc(ref Message m) {
            switch (m.Msg) {
                case BCM_SETDROPDOWNSTATE:
                    if (m.HWnd == Handle) {
                        if (m.WParam.ToString() == "1") {
                            if (m_IsDropDownPushed == 0) {
                                m_IsDropDownPushed = 1;
                                ShowMenu();
                            }
                        }

                        if (m_IsMouseDown == 1) {
                            m_IsAtDropDown = 1;
                        }
                    }
                    break;
                case WM_PAINT:
                    if (m_IsDropDownPushed == 1) {
                        SetDropDownState(1);
                    }
                    break;
                case WM_LBUTTONDOWN:
                    m_IsMouseDown = 1;
                    break;
                case WM_MOUSELEAVE:
                    if (m_IsAtDropDown == 1) {
                        SetDropDownState(0);
                        m_IsAtDropDown = 0;
                        m_IsMouseDown = 0;
                    }
                    break;
                case WM_LBUTTONUP:
                    if (m_IsAtDropDown == 1) {
                        SetDropDownState(0);
                        m_IsAtDropDown = 0;
                        m_IsMouseDown = 0;
                    }
                    break;
                case WM_KILLFOCUS:
                    if (m_IsAtDropDown == 1) {
                        SetDropDownState(0);
                        m_IsAtDropDown = 0;
                        m_IsMouseDown = 0;
                    }
                    break;
            }

            base.WndProc(ref m);
        }

        #endregion
    }
}